package com.fosun.spr.core.interceptor;

import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.MediaType;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fosun.spr.core.constants.BaseConstants;
import com.fosun.spr.core.constants.DataConstants;
import com.fosun.spr.core.constants.SystemLog;
import com.fosun.spr.core.exception.ServiceException;
import com.fosun.spr.core.message.ResultCode;
import com.fosun.spr.core.proxy.annotation.SprControllerLog;
import com.fosun.spr.core.utils.ExtDateUtils;
import com.fosun.spr.core.utils.ExtXmlUtils;
 

/**
 * 
 * @Title: DeviceInterceptor.java
 * @Description:hander拦截
 * @author zhangcheng
 * @date 2017年3月7日 下午6:15:55
 * @version V1.0
 * 
 */
public class DeviceInterceptor extends HandlerInterceptorAdapter {

	protected static final Logger logger = LoggerFactory
			.getLogger(DeviceInterceptor.class);

	private String http;
	private String requested;

	@Override
	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		printRequest(request);
		return super.preHandle(request, response, handler);
	}

	// 后处理（返回ModelAndView，但未进行页面渲染ModelAndView）
	@Override
	public void postHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler,
			ModelAndView modelAndView) throws Exception {

		// 拦截h'andleMethod
		if (handler instanceof HandlerMethod) {
			setHandlerMethod(request, response, (HandlerMethod) handler,
					modelAndView);
		}
		super.postHandle(request, response, handler, modelAndView);
	}
	private void printRequest(HttpServletRequest request){
		StringBuffer sb = new StringBuffer();
		SystemLog systemLog = new SystemLog(getHttp() + request.getServerName() 
				+ ":" + request.getServerPort() + request.getRequestURI(),
				request.getMethod(), (StringUtils.isBlank(request
						.getHeader(getRequested())) ? false : true),
				request.getRemoteAddr(),request.getMethod());
		logger.info("-----------------------------------");
		logger.info("Control HttpInfo ：\r\n      {}",
				JSONObject.toJSONString(systemLog));
		Enumeration<String> names = request.getParameterNames(); 
		while (names.hasMoreElements()) {
			String name = names.nextElement();
			logger.info("    "+name+"=" + request.getParameter(name));
		}
	}

	private ModelAndView setHandlerMethod(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handleMethod,
			ModelAndView modelAndView) {

		
		Method method = handleMethod.getMethod();
		String methodName = method.getName();
		String simpleName = method.getReturnType().getSimpleName();
		
		//replace by chensm @ 20170616
		//Object value = LocalCache.getInstance().get(methodName);
		Object value = modelAndView.getModel().get(StringUtils.uncapitalize(method.getReturnType().getSimpleName()));
		
		verifyJsonData(methodName, value);
		String path = request.getServletPath();
		String[] pathSplit = StringUtils.split(path, BaseConstants.FULL_STOP);
		if (pathSplit.length == DataConstants.NUM_1
				|| StringUtils.equalsIgnoreCase(pathSplit[DataConstants.NUM_1],
						BaseConstants.HEAD_API)) {// 默认json
			writeJsonData(modelAndView, response, simpleName);
		} else {
			SprControllerLog sprControllerLog = handleMethod
					.getMethodAnnotation(SprControllerLog.class);
			String sprPath = StringUtils.trimToEmpty(sprControllerLog.modules());
			if (StringUtils.equalsIgnoreCase(pathSplit[DataConstants.NUM_1],
					BaseConstants.HEAD_VIEW)) {
				sprPath = (sprPath == "") ? (methodName) : (sprPath
						+ BaseConstants.SLASH + methodName);
				writeViewData(modelAndView, sprPath, value);
			} else if (StringUtils.equalsIgnoreCase(
					pathSplit[DataConstants.NUM_1], BaseConstants.HEAD_XML)) {
				writeXmlData(modelAndView, response, method.getReturnType(),
						simpleName);
			} else {
				throw new ServiceException("暂不支持该请求格式!");
			}
		}
		return modelAndView;
	}

	private void verifyJsonData(String methodName, Object value)
			throws ServiceException {
		if (value == null) {
			logger.error(
					"method name:{},errorMsg:[thought request method get return val is fail]",
					methodName);
			throw new ServiceException(ResultCode.SERVER_INNER_ERROR);
		}
	}

	private void writeViewData(ModelAndView view, String methodName,
			Object value) {

		view.setViewName(methodName);
		view.addObject(BaseConstants.FOSUN_MODEL, JSONObject.parseObject(
				JSONObject.toJSONStringWithDateFormat(value,
						ExtDateUtils.TIMESTAMP_FORMAT,
						SerializerFeature.WriteDateUseDateFormat), Map.class));// 返回对象封装成map
	}

	private ModelAndView writeXmlData(ModelAndView modelAndView,
			HttpServletResponse response, Class<?> returnType, String methodName) {

		try {

			Object obj = returnType.newInstance();
			String modelBean = StringUtils
					.lowerCase(methodName.substring(0, 1))
					+ methodName.substring(1);
			String jsonStr = JSONObject.toJSONString(modelAndView.getModelMap()
					.get(modelBean));
			String xmlStr = ExtXmlUtils.convertToXml(JSONObject.parseObject(
					jsonStr, obj.getClass()));
			writeJson2Response(response, xmlStr);
			modelAndView.clear();
		} catch (Exception e) {
			throw new ServiceException("model change xml is error,failMsg{}:"
					+ e.getMessage());
		}
		return modelAndView;
	}

	@SuppressWarnings("unchecked")
	private ModelAndView writeJsonData(ModelAndView modelAndView,HttpServletResponse response,
			String methodName) {
		String modelBean = StringUtils.lowerCase(methodName.substring(0, 1))
				+ methodName.substring(1);
		String returnStr = JSONObject.toJSONString(modelAndView.getModelMap()
				.get(modelBean));
		try {
			writeJson2Response(response,returnStr);
			modelAndView.clear();
		} catch (Exception e) {
			e.printStackTrace();
		}
		logger.info("Control json-srModel:\r\n      " + returnStr);
		return modelAndView;
	}

	private void writeJson2Response(HttpServletResponse response, String json)
			throws IOException {
		response.setContentType(MediaType.APPLICATION_JSON_VALUE);
		response.setCharacterEncoding(BaseConstants.UTF_8);
		PrintWriter writer = response.getWriter();
		writer.write(json);
		writer.flush();
	}

	public String getHttp() {
		return http;
	}

	public void setHttp(String http) {
		this.http = http;
	}

	public String getRequested() {
		return requested;
	}

	public void setRequested(String requested) {
		this.requested = requested;
	}
	
	public class JsonModelView implements View{
		private String json;
		public JsonModelView(String json){
			this.json = json;
		}
		@Override
		public void render(Map<String, ?> model,
				HttpServletRequest request, HttpServletResponse response)
				throws Exception {
			PrintWriter out = response.getWriter();
			out.print(this.json);
		}
		@Override
		public String getContentType() {
			return "application/json;charset=UTF-8";
		}		
	}
}
